// RFC 3315 - 5.5 Timeout and Delay values
static struct dhcpv6_retx dhcpv6_retx[_DHCPV6_MSG_MAX] = {
[DHCPV6_MSG_UNKNOWN] = {false, 1, 120, 0, "<POLL>",
- dhcpv6_handle_reconfigure, NULL, false, 0, 0, 0, {0, 0, 0}, 0, 0, 0, -1},
+ dhcpv6_handle_reconfigure, NULL, false, 0, 0, 0, {0, 0, 0}, 0, 0, 0, -1, 0},
[DHCPV6_MSG_SOLICIT] = {true, 1, DHCPV6_SOL_MAX_RT, 0, "SOLICIT",
- dhcpv6_handle_advert, dhcpv6_commit_advert, false, 0, 0, 0, {0, 0, 0}, 0, 0, 0, -1},
+ dhcpv6_handle_advert, dhcpv6_commit_advert, false, 0, 0, 0, {0, 0, 0}, 0, 0, 0, -1, 0},
[DHCPV6_MSG_REQUEST] = {true, 1, DHCPV6_REQ_MAX_RT, 10, "REQUEST",
- dhcpv6_handle_reply, NULL, false, 0, 0, 0, {0, 0, 0}, 0, 0, 0, -1},
+ dhcpv6_handle_reply, NULL, false, 0, 0, 0, {0, 0, 0}, 0, 0, 0, -1, 0},
[DHCPV6_MSG_RENEW] = {false, 10, DHCPV6_REN_MAX_RT, 0, "RENEW",
- dhcpv6_handle_reply, NULL, false, 0, 0, 0, {0, 0, 0}, 0, 0, 0, -1},
+ dhcpv6_handle_reply, NULL, false, 0, 0, 0, {0, 0, 0}, 0, 0, 0, -1, 0},
[DHCPV6_MSG_REBIND] = {false, 10, DHCPV6_REB_MAX_RT, 0, "REBIND",
- dhcpv6_handle_rebind_reply, NULL, false, 0, 0, 0, {0, 0, 0}, 0, 0, 0, -1},
- [DHCPV6_MSG_RELEASE] = {false, 1, 0, 5, "RELEASE", NULL, NULL, false, 0, 0, 0, {0, 0, 0}, 0, 0, 0, -1},
- [DHCPV6_MSG_DECLINE] = {false, 1, 0, 5, "DECLINE", NULL, NULL, false, 0, 0, 0,{0, 0, 0}, 0, 0, 0, -1},
+ dhcpv6_handle_rebind_reply, NULL, false, 0, 0, 0, {0, 0, 0}, 0, 0, 0, -1, 0},
+ [DHCPV6_MSG_RELEASE] = {false, 1, 0, 5, "RELEASE", NULL, NULL, false, 0, 0, 0, {0, 0, 0}, 0, 0, 0, -1, 0},
+ [DHCPV6_MSG_DECLINE] = {false, 1, 0, 5, "DECLINE", NULL, NULL, false, 0, 0, 0,{0, 0, 0}, 0, 0, 0, -1, 0},
[DHCPV6_MSG_INFO_REQ] = {true, 1, DHCPV6_INF_MAX_RT, 0, "INFOREQ",
- dhcpv6_handle_reply, NULL, false, 0, 0, 0, {0, 0, 0}, 0, 0, 0, -1},
+ dhcpv6_handle_reply, NULL, false, 0, 0, 0, {0, 0, 0}, 0, 0, 0, -1, 0},
};
// Sockets
// Server unicast address
static struct in6_addr server_addr = IN6ADDR_ANY_INIT;
+// Initial state of the dhcpv6
+static enum dhcpv6_state dhcpv6_state = DHCPV6_INIT;
+static int dhcpv6_state_timeout = 0;
+
// Reconfigure key
static uint8_t reconf_key[16];
return ntohl(buf);
}
+static void dhcpv6_next_state(void)
+{
+ dhcpv6_state++;
+ dhcpv6_reset_state_timeout();
+}
+
+static void dhcpv6_prev_state(void)
+{
+ dhcpv6_state--;
+ dhcpv6_reset_state_timeout();
+}
+
static char *dhcpv6_msg_to_str(enum dhcpv6_msg msg)
{
switch (msg) {
return 0;
}
+int dhcpv6_get_socket(void)
+{
+ return sock;
+}
+
+enum dhcpv6_state dhcpv6_get_state(void)
+{
+ return dhcpv6_state;
+}
+
+void dhcpv6_set_state(enum dhcpv6_state state)
+{
+ dhcpv6_state = state;
+ dhcpv6_reset_state_timeout();
+}
+
+int dhcpv6_get_state_timeout(void)
+{
+ return dhcpv6_state_timeout;
+}
+
+void dhcpv6_set_state_timeout(int timeout)
+{
+ if (timeout > 0 && (dhcpv6_state_timeout == 0 || timeout < dhcpv6_state_timeout)) {
+ dhcpv6_state_timeout = timeout;
+ }
+}
+
+void dhcpv6_reset_state_timeout(void)
+{
+ dhcpv6_state_timeout = 0;
+}
+
int init_dhcpv6(const char *ifname, unsigned int options, int sk_prio, int sol_timeout, unsigned int dscp)
{
client_options = options;
return (time * ((int64_t)random % 1000LL)) / 10000LL;
}
-int dhcpv6_request(enum dhcpv6_msg type)
-{
- uint8_t rc = 0;
- uint64_t timeout = UINT32_MAX;
- struct dhcpv6_retx *retx = &dhcpv6_retx[type];
-
- if (retx->delay) {
- struct timespec ts = {0, 0};
- ts.tv_nsec = (dhcpv6_rand_delay((10000 * DHCPV6_REQ_DELAY) / 2) + (1000 * DHCPV6_REQ_DELAY) / 2) * 1000000;
-
- while (nanosleep(&ts, &ts) < 0 && errno == EINTR);
- }
-
- if (type == DHCPV6_MSG_UNKNOWN)
- timeout = t1;
- else if (type == DHCPV6_MSG_RENEW)
- timeout = (t2 > t1) ? t2 - t1 : ((t1 == UINT32_MAX) ? UINT32_MAX : 0);
- else if (type == DHCPV6_MSG_REBIND)
- timeout = (t3 > t2) ? t3 - t2 : ((t2 == UINT32_MAX) ? UINT32_MAX : 0);
-
- if (timeout == 0)
- return -1;
-
- syslog(LOG_NOTICE, "Starting %s transaction (timeout %"PRIu64"s, max rc %d)",
- retx->name, timeout, retx->max_rc);
-
- uint64_t start = odhcp6c_get_milli_time(), round_start = start, elapsed;
-
- // Generate transaction ID
- uint8_t trid[3] = {0, 0, 0};
- if (type != DHCPV6_MSG_UNKNOWN)
- odhcp6c_random(trid, sizeof(trid));
-
- ssize_t len = -1;
- int64_t rto = 0;
-
- do {
- if (rto == 0) {
- int64_t delay = dhcpv6_rand_delay(retx->init_timeo * 1000);
-
- // First RT MUST be strictly greater than IRT for solicit messages (RFC3313 17.1.2)
- while (type == DHCPV6_MSG_SOLICIT && delay <= 0)
- delay = dhcpv6_rand_delay(retx->init_timeo * 1000);
-
- rto = (retx->init_timeo * 1000 + delay);
- } else
- rto = (2 * rto + dhcpv6_rand_delay(rto));
-
- if (retx->max_timeo && (rto >= retx->max_timeo * 1000))
- rto = retx->max_timeo * 1000 +
- dhcpv6_rand_delay(retx->max_timeo * 1000);
-
- // Calculate end for this round and elapsed time
- uint64_t round_end = round_start + rto;
- elapsed = round_start - start;
-
- // Don't wait too long if timeout differs from infinite
- if ((timeout != UINT32_MAX) && (round_end - start > timeout * 1000))
- round_end = timeout * 1000 + start;
-
- // Built and send package
- switch (type) {
- case DHCPV6_MSG_UNKNOWN:
- break;
- default:
- syslog(LOG_NOTICE, "Send %s message (elapsed %"PRIu64"ms, rc %d)",
- retx->name, elapsed, rc);
- // Fall through
- case DHCPV6_MSG_SOLICIT:
- case DHCPV6_MSG_INFO_REQ:
- dhcpv6_send(type, trid, elapsed / 10);
- rc++;
- }
-
- // Receive rounds
- for (; len < 0 && (round_start < round_end);
- round_start = odhcp6c_get_milli_time()) {
- uint8_t buf[1536];
- union {
- struct cmsghdr hdr;
- uint8_t buf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
- } cmsg_buf;
- struct iovec iov = {buf, sizeof(buf)};
- struct sockaddr_in6 addr;
- struct msghdr msg = {.msg_name = &addr, .msg_namelen = sizeof(addr),
- .msg_iov = &iov, .msg_iovlen = 1, .msg_control = cmsg_buf.buf,
- .msg_controllen = sizeof(cmsg_buf)};
- struct in6_pktinfo *pktinfo = NULL;
- const struct dhcpv6_header *hdr = (const struct dhcpv6_header *)buf;
-
- // Check for pending signal
- if (odhcp6c_signal_process())
- return -1;
-
- // Set timeout for receiving
- uint64_t t = round_end - round_start;
- struct timeval tv = {t / 1000, (t % 1000) * 1000};
- if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO,
- &tv, sizeof(tv)) < 0)
- syslog(LOG_ERR, "setsockopt SO_RCVTIMEO failed (%s)",
- strerror(errno));
-
- // Receive cycle
- len = recvmsg(sock, &msg, 0);
- if (len < 0)
- continue;
-
- for (struct cmsghdr *ch = CMSG_FIRSTHDR(&msg); ch != NULL;
- ch = CMSG_NXTHDR(&msg, ch)) {
- if (ch->cmsg_level == SOL_IPV6 &&
- ch->cmsg_type == IPV6_PKTINFO) {
- pktinfo = (struct in6_pktinfo *)CMSG_DATA(ch);
- break;
- }
- }
-
- if (pktinfo == NULL) {
- len = -1;
- continue;
- }
-
- if (!dhcpv6_response_is_valid(buf, len, trid,
- type, &pktinfo->ipi6_addr)) {
- len = -1;
- continue;
- }
-
- uint8_t *opt = &buf[4];
- uint8_t *opt_end = opt + len - 4;
-
- round_start = odhcp6c_get_milli_time();
- elapsed = round_start - start;
- syslog(LOG_NOTICE, "Got a valid %s after %"PRIu64"ms",
- dhcpv6_msg_to_str(hdr->msg_type), elapsed);
-
- if (retx->handler_reply)
- len = retx->handler_reply(type, rc, opt, opt_end, &addr);
-
- if (len > 0 && round_end - round_start > 1000)
- round_end = 1000 + round_start;
- }
-
- // Allow
- if (retx->handler_finish)
- len = retx->handler_finish();
- } while (len < 0 && ((timeout == UINT32_MAX) || (elapsed / 1000 < timeout)) &&
- (!retx->max_rc || rc < retx->max_rc));
- return len;
-}
-
// Message validation checks according to RFC3315 chapter 15
static bool dhcpv6_response_is_valid(const void *buf, ssize_t len,
const uint8_t transaction[3], enum dhcpv6_msg type,
return clientid_ok && serverid_ok;
}
-int dhcpv6_poll_reconfigure(void)
-{
- int ret = dhcpv6_request(DHCPV6_MSG_UNKNOWN);
-
- switch (ret) {
- /*
- * Only RENEW/REBIND/INFORMATION REQUEST
- * message transmission can be requested
- * by a RECONFIGURE
- */
- case DHCPV6_MSG_RENEW:
- case DHCPV6_MSG_REBIND:
- case DHCPV6_MSG_INFO_REQ:
- ret = dhcpv6_request(ret);
- break;
-
- default:
- break;
- }
-
- return ret;
-}
-
static int dhcpv6_handle_reconfigure(enum dhcpv6_msg orig, const int rc,
const void *opt, const void *end, _unused const struct sockaddr_in6 *from)
{
switch (orig) {
case DHCPV6_MSG_RENEW:
case DHCPV6_MSG_REBIND:
- if ((*ret > 0) && !handled_status_codes[code])
- *ret = dhcpv6_request(DHCPV6_MSG_REQUEST);
+ if ((*ret > 0) && !handled_status_codes[code]) {
+ dhcpv6_set_state(DHCPV6_REQUEST);
+ *ret = -1;
+ }
break;
default:
dhcpv6_retx[DHCPV6_MSG_SOLICIT].max_timeo = cand->sol_max_rt;
dhcpv6_retx[DHCPV6_MSG_INFO_REQ].max_timeo = cand->inf_max_rt;
- return dhcpv6_request(DHCPV6_MSG_SOLICIT);
+ dhcpv6_set_state(DHCPV6_SOLICIT);
+ return -1;
}
hdr[0] = htons(DHCPV6_OPT_SERVERID);
int dhcpv6_send_request(enum dhcpv6_msg type)
{
struct dhcpv6_retx *retx = &dhcpv6_retx[type];
+ uint64_t current_milli_time = 0;
+
+ if (retx->delay ) {
+ if (retx->delay_msec == 0) {
+ retx->delay_msec = (dhcpv6_rand_delay((10000 * DHCPV6_REQ_DELAY) / 2) + (1000 * DHCPV6_REQ_DELAY) / 2);
+ dhcpv6_set_state_timeout(retx->delay_msec);
+ retx->delay_msec += odhcp6c_get_milli_time();
+ return 1;
+ } else {
+ current_milli_time = odhcp6c_get_milli_time();
+ if (current_milli_time < retx->delay_msec) {
+ dhcpv6_set_state_timeout(retx->delay_msec - current_milli_time);
+ return 1;
+ }
+ retx->delay_msec = 0;
+ }
+ }
if (!retx->is_retransmit) {
retx->is_retransmit = true;
retx->rc = 0;
retx->timeout = UINT32_MAX;
-
- if (retx->delay) {
- struct timespec ts = {0, 0};
- ts.tv_nsec = (dhcpv6_rand_delay((10000 * DHCPV6_REQ_DELAY) / 2) + (1000 * DHCPV6_REQ_DELAY) / 2) * 1000000;
- while (nanosleep(&ts, &ts) < 0 && errno == EINTR);
- }
+ retx->reply_ret = -1;
if (type == DHCPV6_MSG_UNKNOWN)
retx->timeout = t1;
if ((retx->timeout != UINT32_MAX) && (retx->round_end - retx->start > retx->timeout * 1000))
retx->round_end = retx->timeout * 1000 + retx->start;
+ dhcpv6_set_state_timeout(retx->round_end - odhcp6c_get_milli_time());
+
// Built and send package
switch (type) {
case DHCPV6_MSG_UNKNOWN:
dhcpv6_send(type, retx->tr_id, elapsed / 10);
retx->rc++;
}
+
+ if (dhcpv6_get_state() != DHCPV6_EXIT)
+ dhcpv6_next_state();
+
return 0;
}
return retx->reply_ret;
}
+
+int dhcpv6_state_processing(enum dhcpv6_msg type)
+{
+ struct dhcpv6_retx *retx = &dhcpv6_retx[type];
+ int ret = retx->reply_ret;
+ retx->round_start = odhcp6c_get_milli_time();
+ uint64_t elapsed = retx->round_start - retx->start;
+
+ if (retx->round_start >= retx->round_end || ret >=0 ) {
+ if (retx->handler_finish)
+ ret = retx->handler_finish();
+
+ if (ret < 0 && ((retx->timeout == UINT32_MAX) || (elapsed / 1000 < retx->timeout)) &&
+ (!retx->max_rc || retx->rc < retx->max_rc)) {
+ retx->reply_ret = -1;
+ dhcpv6_prev_state();
+ } else {
+ retx->is_retransmit = false;
+ dhcpv6_next_state();
+ }
+ } else {
+ dhcpv6_set_state_timeout(retx->round_end - retx->round_start);
+ }
+
+ return ret;
+}
#include <net/if.h>
#include <sys/syscall.h>
+#include <poll.h>
#include <arpa/inet.h>
#include <linux/if_addr.h>
int verbosity = 0;
bool help = false, daemonize = false;
int logopt = LOG_PID;
- int c, res;
+ int c;
+ int res = -1;
unsigned int client_options = DHCPV6_CLIENT_FQDN | DHCPV6_ACCEPT_RECONFIGURE;
unsigned int ra_options = RA_RDNSS_DEFAULT_LIFETIME;
unsigned int ra_holdoff_interval = RA_MIN_ADV_INTERVAL;
unsigned int dscp = 0;
+ bool terminate = false;
while ((c = getopt(argc, argv, "S::DN:V:P:FB:c:i:r:Ru:Ux:s:kK:t:C:m:Lhedp:fav")) != -1) {
switch (c) {
return 4;
}
- script_call("started", 0, false);
+ struct pollfd fds[2] = {0};
+ int nfds = 0;
- while (!signal_term) { // Main logic
- odhcp6c_clear_state(STATE_SERVER_ID);
- odhcp6c_clear_state(STATE_SERVER_ADDR);
- odhcp6c_clear_state(STATE_IA_NA);
- odhcp6c_clear_state(STATE_IA_PD);
- odhcp6c_clear_state(STATE_SNTP_IP);
- odhcp6c_clear_state(STATE_NTP_IP);
- odhcp6c_clear_state(STATE_NTP_FQDN);
- odhcp6c_clear_state(STATE_SIP_IP);
- odhcp6c_clear_state(STATE_SIP_FQDN);
- bound = false;
+ int dhcpv6_socket = dhcpv6_get_socket();
+ int mode = DHCPV6_UNKNOWN;
+ enum dhcpv6_msg msg_type = DHCPV6_MSG_UNKNOWN;
- syslog(LOG_NOTICE, "(re)starting transaction on %s", ifname);
-
- signal_usr1 = signal_usr2 = false;
- int mode = dhcpv6_set_ia_mode(ia_na_mode, ia_pd_mode, stateful_only_mode);
- if (mode != DHCPV6_STATELESS)
- mode = dhcpv6_request(DHCPV6_MSG_SOLICIT);
+ if (dhcpv6_socket < 0) {
+ syslog(LOG_ERR, "Invalid dhcpv6 file descriptor");
+ return 1;
+ }
+
+ fds[nfds].fd = dhcpv6_socket;
+ fds[nfds].events = POLLIN;
+ nfds++;
+
+ script_call("started", 0, false);
+
+ while (!terminate) { // Main logic
+ int poll_res;
+ bool signalled = odhcp6c_signal_process();
+
+ switch (dhcpv6_get_state()) {
+ case DHCPV6_INIT:
+ odhcp6c_clear_state(STATE_SERVER_ID);
+ odhcp6c_clear_state(STATE_SERVER_ADDR);
+ odhcp6c_clear_state(STATE_IA_NA);
+ odhcp6c_clear_state(STATE_IA_PD);
+ odhcp6c_clear_state(STATE_SNTP_IP);
+ odhcp6c_clear_state(STATE_NTP_IP);
+ odhcp6c_clear_state(STATE_NTP_FQDN);
+ odhcp6c_clear_state(STATE_SIP_IP);
+ odhcp6c_clear_state(STATE_SIP_FQDN);
+ bound = false;
+
+ syslog(LOG_NOTICE, "(re)starting transaction on %s", ifname);
+
+ signal_usr1 = signal_usr2 = false;
+ dhcpv6_set_state(DHCPV6_SOLICIT);
+ break;
- odhcp6c_signal_process();
+ case DHCPV6_SOLICIT:
+ mode = dhcpv6_set_ia_mode(ia_na_mode, ia_pd_mode, stateful_only_mode);
+ if (mode == DHCPV6_STATELESS) {
+ dhcpv6_set_state(DHCPV6_REQUEST);
+ break;
+ }
+
+ msg_type = DHCPV6_MSG_SOLICIT;
+ dhcpv6_send_request(msg_type);
+ break;
- if (mode < 0)
- continue;
+ case DHCPV6_ADVERT:
+ if (res > 0) {
+ mode = DHCPV6_STATEFUL;
+ dhcpv6_set_state(DHCPV6_REQUEST);
+ } else {
+ mode = DHCPV6_UNKNOWN;
+ dhcpv6_set_state(DHCPV6_INIT);
+ }
+ break;
- do {
- res = dhcpv6_request(mode == DHCPV6_STATELESS ?
- DHCPV6_MSG_INFO_REQ : DHCPV6_MSG_REQUEST);
- bool signalled = odhcp6c_signal_process();
+ case DHCPV6_REQUEST:
+ msg_type = (mode == DHCPV6_STATELESS) ? DHCPV6_MSG_INFO_REQ : DHCPV6_MSG_REQUEST;
+ dhcpv6_send_request(msg_type);
+ break;
- if (res > 0)
+ case DHCPV6_REPLY:
+ if ((res > 0) && mode != DHCPV6_UNKNOWN) {
+ dhcpv6_set_state(DHCPV6_BOUND);
break;
- else if (signalled) {
- mode = -1;
+ }
+
+ if ((res < 0) && signalled) {
+ mode = DHCPV6_UNKNOWN;
+ dhcpv6_set_state(DHCPV6_INIT);
break;
}
mode = dhcpv6_promote_server_cand();
- } while (mode > DHCPV6_UNKNOWN);
-
- if (mode < 0)
- continue;
-
- switch (mode) {
- case DHCPV6_STATELESS:
- bound = true;
- syslog(LOG_NOTICE, "entering stateless-mode on %s", ifname);
-
- while (!signal_usr2 && !signal_term) {
- signal_usr1 = false;
- script_call("informed", ra ? script_accu_delay : script_sync_delay, true);
-
- res = dhcpv6_poll_reconfigure();
- odhcp6c_signal_process();
-
- if (res > 0)
- continue;
+ dhcpv6_set_state(mode > DHCPV6_UNKNOWN ? DHCPV6_REQUEST : DHCPV6_INIT);
+ break;
- if (signal_usr1) {
- signal_usr1 = false; // Acknowledged
- continue;
+ case DHCPV6_BOUND:
+ if (!bound) {
+ bound = true;
+ if (mode == DHCPV6_STATELESS) {
+ syslog(LOG_NOTICE, "entering stateless-mode on %s", ifname);
+ signal_usr1 = false;
+ script_call("informed", script_sync_delay, true);
+ } else {
+ script_call("bound", script_sync_delay, true);
+ syslog(LOG_NOTICE, "entering stateful-mode on %s", ifname);
}
+ }
- if (signal_usr2 || signal_term)
- break;
-
- res = dhcpv6_request(DHCPV6_MSG_INFO_REQ);
- odhcp6c_signal_process();
-
- if (signal_usr1)
- continue;
- else if (res < 0)
- break;
+ msg_type = DHCPV6_MSG_UNKNOWN;
+ dhcpv6_send_request(msg_type);
+ break;
+
+ case DHCPV6_BOUND_REPLY:
+ if (res == DHCPV6_MSG_RENEW || res == DHCPV6_MSG_REBIND ||
+ res == DHCPV6_MSG_INFO_REQ) {
+ msg_type = res;
+ dhcpv6_set_state(DHCPV6_RECONF);
+ } else {
+ dhcpv6_set_state(DHCPV6_RECONF_REPLY);
}
break;
- case DHCPV6_STATEFUL:
- bound = true;
- script_call("bound", ra ? script_accu_delay : script_sync_delay, true);
- syslog(LOG_NOTICE, "entering stateful-mode on %s", ifname);
-
- while (!signal_usr2 && !signal_term) {
- // Renew Cycle
- // Wait for T1 to expire or until we get a reconfigure
- res = dhcpv6_poll_reconfigure();
- odhcp6c_signal_process();
- if (res > 0) {
- script_call("updated", 0, false);
- continue;
- }
+ case DHCPV6_RECONF:
+ dhcpv6_send_request(msg_type);
+ break;
- // Handle signal, if necessary
- if (signal_usr1)
- signal_usr1 = false; // Acknowledged
+ case DHCPV6_RECONF_REPLY:
+ if (res > 0) {
+ dhcpv6_set_state(DHCPV6_BOUND);
+ if (mode == DHCPV6_STATEFUL)
+ script_call("updated", 0, false);
+ } else {
+ dhcpv6_set_state(mode == DHCPV6_STATELESS ? DHCPV6_INFO : DHCPV6_RENEW);
+ }
+ break;
+
+ case DHCPV6_RENEW:
+ msg_type = DHCPV6_MSG_RENEW;
+ dhcpv6_send_request(msg_type);
+ break;
+
+ case DHCPV6_RENEW_REPLY:
+ if (res > 0 ) {
+ script_call("updated", 0, false);
+ dhcpv6_set_state(DHCPV6_BOUND);
+ } else {
+ dhcpv6_set_state(DHCPV6_REBIND);
+ }
+ break;
- if (signal_usr2 || signal_term)
- break; // Other signal type
+ case DHCPV6_REBIND:
+ odhcp6c_clear_state(STATE_SERVER_ID); // Remove binding
+ odhcp6c_clear_state(STATE_SERVER_ADDR);
- // Send renew as T1 expired
- res = dhcpv6_request(DHCPV6_MSG_RENEW);
- odhcp6c_signal_process();
+ size_t ia_pd_len_r, ia_na_len_r;
+ odhcp6c_get_state(STATE_IA_PD, &ia_pd_len_r);
+ odhcp6c_get_state(STATE_IA_NA, &ia_na_len_r);
- if (res > 0) { // Renew was succesfull
- // Publish updates
- script_call("updated", 0, false);
- continue; // Renew was successful
- }
+ if (ia_pd_len_r == 0 && ia_na_len_r == 0) {
+ dhcpv6_set_state(DHCPV6_EXIT);
+ break;
+ }
- odhcp6c_clear_state(STATE_SERVER_ID); // Remove binding
- odhcp6c_clear_state(STATE_SERVER_ADDR);
+ // If we have IAs, try rebind otherwise restart
+ msg_type = DHCPV6_MSG_REBIND;
+ dhcpv6_send_request(msg_type);
+ break;
+
+ case DHCPV6_REBIND_REPLY:
+ if (res < 0) {
+ dhcpv6_set_state(DHCPV6_EXIT);
+ } else {
+ script_call("rebound", 0, true);
+ dhcpv6_set_state(DHCPV6_BOUND);
+ }
+ break;
- // Remove any state invalidated by RENEW reply
- odhcp6c_expire(true);
+ case DHCPV6_INFO:
+ msg_type = DHCPV6_MSG_INFO_REQ;
+ dhcpv6_send_request(msg_type);
+ break;
+
+ case DHCPV6_INFO_REPLY:
+ dhcpv6_set_state(res < 0 ? DHCPV6_EXIT : DHCPV6_BOUND);
+ break;
- size_t ia_pd_len, ia_na_len;
- odhcp6c_get_state(STATE_IA_PD, &ia_pd_len);
- odhcp6c_get_state(STATE_IA_NA, &ia_na_len);
+ case DHCPV6_SOLICIT_PROCESSING:
+ case DHCPV6_REQUEST_PROCESSING:
+ res = dhcpv6_state_processing(msg_type);
- if (ia_pd_len == 0 && ia_na_len == 0)
- break;
+ if (signal_usr2 || signal_term)
+ dhcpv6_set_state(DHCPV6_EXIT);
+ break;
- // If we have IAs, try rebind otherwise restart
- res = dhcpv6_request(DHCPV6_MSG_REBIND);
- odhcp6c_signal_process();
+ case DHCPV6_BOUND_PROCESSING:
+ case DHCPV6_RECONF_PROCESSING:
+ case DHCPV6_REBIND_PROCESSING:
+ res = dhcpv6_state_processing(msg_type);
- if (res > 0)
- script_call("rebound", 0, true);
- else
- break;
+ if (signal_usr1)
+ dhcpv6_set_state(mode == DHCPV6_STATELESS ? DHCPV6_INFO : DHCPV6_RENEW);
+ if (signal_usr2 || signal_term)
+ dhcpv6_set_state(DHCPV6_EXIT);
+ break;
+
+ case DHCPV6_RENEW_PROCESSING:
+ case DHCPV6_INFO_PROCESSING:
+ res = dhcpv6_state_processing(msg_type);
+
+ if (signal_usr1)
+ signal_usr1 = false; // Acknowledged
+ if (signal_usr2 || signal_term)
+ dhcpv6_set_state(DHCPV6_EXIT);
+ break;
+
+ case DHCPV6_EXIT:
+ odhcp6c_expire(false);
+
+ size_t ia_pd_len, ia_na_len, server_id_len;
+ odhcp6c_get_state(STATE_IA_PD, &ia_pd_len);
+ odhcp6c_get_state(STATE_IA_NA, &ia_na_len);
+ odhcp6c_get_state(STATE_SERVER_ID, &server_id_len);
+
+ // Add all prefixes to lost prefixes
+ bound = false;
+ script_call("unbound", 0, true);
+
+ if (server_id_len > 0 && (ia_pd_len > 0 || ia_na_len > 0) && release)
+ dhcpv6_send_request(DHCPV6_MSG_RELEASE);
+
+ odhcp6c_clear_state(STATE_IA_NA);
+ odhcp6c_clear_state(STATE_IA_PD);
+
+ if (!signal_usr2) {
+ terminate = true;
+ } else {
+ signal_usr2 = false;
+ dhcpv6_set_state(DHCPV6_INIT);
}
break;
break;
}
- odhcp6c_expire(false);
-
- size_t ia_pd_len, ia_na_len, server_id_len;
- odhcp6c_get_state(STATE_IA_PD, &ia_pd_len);
- odhcp6c_get_state(STATE_IA_NA, &ia_na_len);
- odhcp6c_get_state(STATE_SERVER_ID, &server_id_len);
-
- // Add all prefixes to lost prefixes
- bound = false;
- script_call("unbound", 0, true);
+ poll_res = poll(fds, nfds, dhcpv6_get_state_timeout());
+ dhcpv6_reset_state_timeout();
+ if (poll_res == -1 && (errno == EINTR || errno == EAGAIN)) {
+ continue;
+ }
- if (server_id_len > 0 && (ia_pd_len > 0 || ia_na_len > 0) && release)
- dhcpv6_request(DHCPV6_MSG_RELEASE);
+ if (fds[0].revents & POLLIN)
+ dhcpv6_receive_response(msg_type);
- odhcp6c_clear_state(STATE_IA_NA);
- odhcp6c_clear_state(STATE_IA_PD);
}
-
script_call("stopped", 0, true);
return 0;